package com.vip.oauth2resource.config;

import com.alibaba.fastjson.JSON;
import com.vip.common.response.ErrorCode;
import com.vip.common.response.RestResponses;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

/**
 * 资源服务器配置
 *
 * @author LEON
 */
@Slf4j
@AllArgsConstructor
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthResourceServerConfig extends ResourceServerConfigurerAdapter {
    /**
     * 自定义安全验证规则
     */
    private final SecurityProperties securityProperties;
    /**
     * 自动注入Redis工厂
     */
    private final RedisConnectionFactory redisConnectionFactory;


    @Bean
    public RedisTokenStore redisTokenStore(RedisConnectionFactory redisConnectionFactory) {
        return new RedisTokenStore(redisConnectionFactory);
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.tokenStore(redisTokenStore(redisConnectionFactory)).stateless(false)
                .authenticationEntryPoint((request, response, authException) -> {
                    response.setStatus(HttpStatus.OK.value());
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                    Throwable cause = authException.getCause();
                    if (cause instanceof InvalidTokenException) {
                        //Token无效
                        log.error("未授权的访问，Token无效：{}", cause.getMessage());
                        response.getWriter().write(JSON.toJSONString(RestResponses.newFailResponse(ErrorCode.ACCESS_TOKEN_INVALID)));
                    } else {
                        //资源未授权
                        log.error("认证异常：没有身份凭证：{}", cause.getMessage());
                        response.getWriter().write(JSON.toJSONString(RestResponses.newFailResponse(ErrorCode.UNAUTHORIZED)));
                    }
                })
                // 权限不足的处理
                .accessDeniedHandler((request, response, e) -> {
                    response.setStatus(HttpStatus.OK.value());
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                    log.error("未授权的访问，访问被拒绝：{}", e.getMessage());
                    response.getWriter().write(JSON.toJSONString(RestResponses.newFailResponse(ErrorCode.INSUFFICIENT_PERMISSIONS)));
                }).resourceId("resource");
    }


    @Override
    public void configure(HttpSecurity http) {
        try {
            http.csrf().disable()
                    .headers().frameOptions().disable().and()
                    .cors().and()
                    .authorizeRequests()
                    .antMatchers(this.securityProperties.getIgnorePaths().split(",")).permitAll()
                    .anyRequest()
                    .authenticated().and()
                    .exceptionHandling()
                    //认证失败的业务处
                    .authenticationEntryPoint((request, response, e) -> {
                        response.setStatus(HttpStatus.OK.value());
                        response.setCharacterEncoding("UTF-8");
                        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                        log.error("未授权的访问：无此权限：{}", e.getMessage());
                        response.getWriter().write(JSON.toJSONString(RestResponses.newFailResponse(ErrorCode.INSUFFICIENT_PERMISSIONS)));
                    });
        } catch (Exception e) {
            log.error("认证出错", e);
        }
    }
}
